#!/usr/bin/perl

# Basic HTML that's specific to blog display elements.
# Not about content so much.

use strict;
use DBI;
package MyApache::POUND::POUNDBLOGHTML;

require Exporter;
require AutoLoader;

use MyApache::POUND::Argpass;
use MyApache::POUND::POUNDHTML;
use MyApache::POUND::POUNDConfig;
use MyApache::POUND::POUNDSession;
use MyApache::POUND::POUNDMarkup;
use MyApache::POUND::POUNDPaths;
use MyApache::POUND::POUNDBLOGDB;
use MyApache::POUND::POUNDUser;

our @ISA = qw(Exporter AutoLoader);
our @EXPORT_OK = qw(display_bnode);
our @EXPORT = @EXPORT_OK;

sub display_bnode
{
my $args = MyApache::POUND::Argpass::new('clean', @_);
my $apache_r	= $args->mandate('apacheobj');
my $nodetype	= $args->mandate('nodetype'); # entry or comment
my $noderef	= $args->mandate('node_r');

my $repliesref 	= $args->mandate('replies_r');
my $deepreplies = $args->mandate('num_deep_replies');
my $zeitinforef = $args->mandate('zeitinfo');
my $replyfield 	= $args->mandate('do_replyfield');
my $reply_ok 	= $args->mandate('reply_ok');
my $blogcfg	= $args->mandate('blogcfg');

my $emisc	= $args->accept('entry_misc', undef); # entry-specific
my $topics 	= $args->accept('entry_topics_list', undef); # entry-specific
my $hidecuts	= $args->accept('hide_cuts', 0);
my $rendermode	= $args->accept('rendermode', 'div');
$args->argok();

my $uid = session_uid(apacheobj => $apache_r);

my @header;
my @hmisc;
my $zeit = $$noderef{zeit};

my $contype = ':';
if($hidecuts)
	{$contype .= 'hidecuts:';}

if(defined($topics) && (@$topics > 0))
	{
	my @th =
		("Topics: ",
		join(', ', 
			map
				{
				get_htlink(
					target => url_topic(blogname => $$blogcfg{name}, topicname => $$_{name}),
					content => $$_{name},
					follow_ok => 1) . "\n";
				} @$topics)
			);
	push(@hmisc, \@th);
	}
if(($nodetype eq 'comment') && defined(my $authorid = $$noderef{author})) # In comments, authors are shown
	{
	my %pinfo = get_personinfo(uid => $authorid);
	my $picbit = '';
	my $authorstring = get_htlink(target => url_person(login_name => $pinfo{login}), content => $pinfo{name}, follow_ok => 1);
	push(@header, \('Author', $authorstring)) ;
	if(defined $pinfo{picurl})
		{ # FIXME This is pretty ugly. Rework somehow.
		my @th = (qq{<img src="} . $pinfo{picurl} . q{" />});
		push(@header, \@th);
		}
	}
if(($nodetype eq 'entry') && defined($emisc)) # Misc stuff for display
	{ # FIXME Right now, fields-to-display are hardcoded here and displayed as text. Consider:
		# 1) Making this specified in a per-blog or global setting in the database
		# 2) Adding a framework defining attributes of fields and how they are to be handled
		#	(e.g. plotting numeric moods over the last few weeks in an autogenerated plot)
		# 3) More intelligently handling when the same field has multiple values (right now each value gets its own line)
	my @fields_to_display = qw/Music Mood/;
	map
		{
		my @th =
			(
			ucfirst(lc(  html_purge(data => $$_{misctype}) )),
			html_purge(data => $$_{miscdata})
			);
		push(@header, \@th);
		}
		sort {$$a{misctype} cmp $$b{misctype}} @$emisc;
	}

my $content;
	{
	my $body = $$noderef{body};
	if($$noderef{private})
		{$body = qq{<div style="privatetext">'''Entry is private'''</div>\n};}
	my $privatetext = qq{\n\n<div class="privatetext">'''PRIVATE SECTION NOT SHOWN'''</div>\n\n};
	$body =~ s/<PRIVATE>.*?<\/PRIVATE>/$privatetext/msig; # XXX I guess comments can do this too, but think more about this..
	$body =~ s/<PRIVATE>.*$/$privatetext (may be more than intended because of unterminated section)/msig;
	$body =~ s/^.*<\/PRIVATE>/$privatetext (may be more than intended because of uninitialised section)/msig;
		# Note that the last two above are "playing it safe" - we'd rather hide too much than reveal too much
		# when the user doesn't properly provide a pair of tags.

	if($nodetype eq 'entry') # FIXME Unify
		{
		$content = do_markup(
			data => $body,
			context => $$blogcfg{name},
			content_flags => $contype,
			cut_target => url_nodepage(blogname => $$blogcfg{name}, nodezeit => $zeit, nodetype => 'entry'));
		}
	else
		{
		$content = do_markup(
			data => $body,
			context => $$blogcfg{name},
			content_flags => $contype);
		}
	}

my @frow;
if($replyfield)
	{ # Eventually also allow ACLs
	my @repfields;
	if(! $reply_ok)
		{
		push(@repfields, 'Replies disabled');
		}
	elsif(session_uid(apacheobj => $apache_r)) # User is logged in
		{
		push(@repfields,
			get_htlink(	target => url_node_reply_page(	blogname => $$blogcfg{name},
									node => $zeit,
									nodetype => $nodetype),
					content => 'Reply')
			);
		}
	else
		{
		push(@repfields,
			get_htlink(	target => url_node_reply_page(	blogname => $$blogcfg{name},
									node => $zeit,
									nodetype => $nodetype),
					content => 'Anon Reply')
			);
		}
	if(($nodetype eq 'entry') && ($uid == $$blogcfg{author})) # If appropriate, let user edit their posts
		{
		push(@repfields, get_htlink(	target => url_edentrypage(	blogname => $$blogcfg{name},
										entryzeit => $zeit), 
						content => "EDIT")
			);

		if($$noderef{private}) # Give people a toggle to deprivate
			{
			push(@repfields, get_htlink(	target => url_entry_toggle_private(	blogname => $$blogcfg{name},
												entryzeit => $zeit,
												to_private => 0), 
							content => "MakePublic"));
			}
		else # and a toggle to enprivate
			{
			push(@repfields, get_htlink(	target => url_entry_toggle_private(	blogname => $$blogcfg{name},
												entryzeit => $zeit,
												to_private => 1), 
							content => "MakePrivate"));
			}
		}
	@frow = (
		get_htlink(
			target => url_nodepage(blogname => $$blogcfg{name}, nodezeit => $zeit, nodetype => $nodetype),
			content => "View $nodetype and replies",
			follow_ok => 1)
		. '('
		. repliessummary(
			num_sreplies => scalar(@$repliesref),
			num_deepreplies => $deepreplies)
		. ")"
		, @repfields);
	}

if($rendermode eq 'table')
	{
	draw_table( # TODO This abstraction is too simple for good-looking representation. Figure out a better one.
		title => $$noderef{title},
		table_class => "jentry", # For nodetype eq comment, should this be jcomment?
		bzeit => $zeit,
		bzeitinfo => $zeitinforef,
		hmisc => \@hmisc,
		content => $content,
		content_class => 'jbody',
		footer_parts => \@frow,
		rendermode => $rendermode,
		rwidth => (scalar(@frow) < 2? 2 : scalar(@frow)));
	}
elsif($rendermode eq 'div')
	{
	print draw_bnode(
		bnode_class => 'jentry',
		bzeit => $zeit,
		bzeitinfo => $zeitinforef,
		title => $$noderef{title},
		hmisc => \@hmisc,
		content => $content,
		footer_fields => \@frow);
	}
else
	{
	errorpage(text => "Bad rendermode");
	}
}

sub repliessummary
{ # If we customize strings, this will need tweaking
my $args = MyApache::POUND::Argpass::new('clean', @_);
my $shallow = $args->mandate('num_sreplies');
my $deep = $args->mandate('num_deepreplies');
$args->argok();

my $returner;
if($shallow == $deep)
	{
	if($shallow == 1)
		{
		$returner = '1 reply';
		}
	else
		{
		$returner = "$shallow replies";
		}
	}
else
	{
	$returner = "$shallow/$deep replies";
	}
return $returner;
}

sub draw_bnode
{ 	# TODO: Remerge with draw_table if possible
	# Draws a node given whatever attributes are available to it.
my $args = MyApache::POUND::Argpass::new('clean', @_);
my $bclass	= $args->accept('bnode_class', undef); # CSS class to apply to the node

my $bzeit	= $args->accept('bzeit', undef);
my $bzeitinfo	= $args->accept('bzeitinfo', undef);

my $btitle	= $args->accept('title', 'Untitled'); # Title for this bnode

my $bmisc	= $args->accept('hmisc', undef); # List of extra field: attribute(s) tuples to display before body
my $bcontent	= $args->mandate('content');
my $bcclass	= $args->accept('content_class', 'jbody');
my $bfooter	= $args->accept('footer_fields', undef); # A list of things to give the user in a single line of footer
$args->argok();

my $btimeimg	= $bzeitinfo ? $$bzeitinfo{imageurl} : undef;
my $btimeimgsz	= $bzeitinfo ? ($$bzeitinfo{imageurlsz} ? $$bzeitinfo{imageurlsz}:38):38; # XXX I think there's a better syntax for this.
my $btimesum	= $bzeitinfo ? ($$bzeitinfo{name} ? $$bzeitinfo{name} : undef) : undef; # Summary for time, e.g. "Afternoon"
my $btimestr	= scalar localtime $bzeit;

my $drawtarg = '';

	{
	my $classblurb = '';
	if($bclass) {$classblurb = qq{ class="$bclass"};}
	$drawtarg .= qq{<div$classblurb>\n}; # TODO Don't forget to migrate this style stuff into the CSS file
	}
$drawtarg .= qq{\t<div class="jehead">\n};

if($btimeimg || $btimesum || $btimestr) # If we have any time data at all, display it
	{
	$drawtarg .= qq{\t\t<div class="jeheadtime">\n};
	if($btimeimg)
		{
		$drawtarg .= qq{\t\t\t<div class="jheadtimev">\n}
			. 	qq{\t\t\t\t<div style="float:left;">\n}
			.		qq{\t\t\t\t\t<img src="$btimeimg"}
			.	 ($btimesum ? (qq{ alt="$btimesum"}):'')
			.		qq{>\n}
			.	 qq{\t\t\t\t</div>\n}
			. 	($btimesum ? (
				qq{\t\t\t\t<div class="jetimedesc">\n}
			.		qq{\t\t\t\t\t$btimesum\n}
			.	qq{\t\t\t\t</div>\n}
				) : '')
			.	qq{\t\t\t</div>\n};
		}
	if($btimestr)
		{
		$drawtarg .= qq{\t\t\t<div class="jeheadtimet">\n}
			.	qq{\t\t\t\t<div class="jetimetext">\n}
			. 	qq{\t\t\t\t\t$btimestr\n}
			.	qq{\t\t\t\t</div>\n}
			.	qq{\t\t\t</div>\n};
		}
	$drawtarg .= qq{\t\t</div>\n};
	}
if($btitle)
	{
	$drawtarg .= qq{\t\t<div class="jetitle">$btitle</div>\n};
	}

if($bmisc)
	{ # $bmisc is a reference to a list of lists, each first-level list is a tuple.
	foreach my $tuple (@$bmisc)
		{
		$drawtarg .= qq{\t\t<div class="jemisc">\n};
		$drawtarg .= qq{\t\t\t<div style="float:left;margin-right:1em;">} . $$tuple[0] . qq{</div>\n};
		foreach my $tuple_i (1 .. $#$tuple)
			{
			$drawtarg .= qq{\t\t\t<div class="jetopic">\n};
			$drawtarg .= qq{\t\t\t\t} . $$tuple[$tuple_i] . qq{\n};
			$drawtarg .= qq{\t\t\t</div>\n}; # XXX Would a CSS list be better?
			}
		$drawtarg .= qq{\t\t</div>\n};
		}
	}
$drawtarg .= qq{\t</div><!-- jehead -->\n}; # close jehead

$drawtarg .= qq{\t<div class="$bcclass">\n};
$drawtarg .= qq{<p>$bcontent</p>\n};
$drawtarg .= qq{\t</div>\n}; # close jehead

if($bfooter)
	{ # $bfooter is a list of stuff that gets packed into a single "line".
	$drawtarg .= qq{\t<div class="jetail">\n};
	foreach my $bfootpart (@$bfooter)
		{
		$drawtarg .= qq{\t\t<span class="jetailfield">$bfootpart</span>\n};
		}
	$drawtarg .= qq{\t</div>\n};
	}
$drawtarg .= qq{</div><br /><br />\n\n};
return $drawtarg;
}

sub draw_table
{ # Draw, with tables, a set of specified content.
  # Right now this is mostly aimed at the kind of boxes the blog uses..
  # TODO: Experiment with alternate "rendermode"s that are DIV-based
my $args = MyApache::POUND::Argpass::new('clean', @_);
my $tclass	= $args->accept('table_class', undef);
my $hmisc	= $args->accept('hmisc', undef);
my $content	= $args->mandate('content');
my $cclass	= $args->accept('content_class', undef);
my $fparts	= $args->accept('footer_parts', undef);
my $rendermode	= $args->accept('rendermode', 'table');
my $rwidth	= $args->accept('rwidth', 2); 	# If specified, pad up to this width
my $btitle	= $args->accept('title', 'Untitled'); # Title for this bnode
my $bzeit	= $args->accept('bzeit', undef);
my $bzeitinfo	= $args->accept('bzeitinfo', undef);
$args->argok();

my $tcinclude;my $ccinclude;
if($tclass)
	{$tcinclude = qq{ class="$tclass"};}
if($cclass)
	{$ccinclude = qq{ class="$cclass"};}

print qq{<table border="1"$tcinclude>\n<tbody>};
if($bzeit && $bzeitinfo)
	{
	my $spaceused = 0;
	my $firstpart = ''; my $secondpart;
	if($$bzeitinfo{imageurl})
		{
		$firstpart = qq.<td><img src="$$bzeitinfo{imageurl}" alt="$$bzeitinfo{name}" />$$bzeitinfo{name}</td>.;
		$spaceused++;
		}
	my $spansize = $rwidth - $spaceused;
	print q{<tr>} . $firstpart . qq{<td colspan=$spansize>} . scalar localtime($bzeit) . qq{</td></tr>\n}
	}
if($btitle)
	{
	print qq{<tr><td colspan=$rwidth>$btitle</td></tr>\n};
	}
if(defined $hmisc)
	{
	foreach my $hpart (@$hmisc)
		{
		print qq{<tr>};
		if((scalar(@$hpart) == 1))
			{print qq{<td colspan=$rwidth>$$hpart[0]</td>};}
		else
			{
			my $length_so_far=0;
			foreach my $h_idx (0 .. $#$hpart-1)
				{
				print q{<td>} . $$hpart[$h_idx] . q{</td>};
				$length_so_far++;
				}
			print qq{<td colspan=} . ($rwidth - $length_so_far + 1) . q{>} . $$hpart[$#$hpart] . q{</td>};
			print qq{</tr>\n};
			}
		}
	}
print qq{<tr><td colspan="$rwidth"$ccinclude>\n$content\n</td></tr>\n};
if(defined $fparts && @$fparts)
	{
	if(defined($rwidth))
		{print qq{<tr colspan=$rwidth>}}
	else
		{print qq{<tr>};}
	foreach my $fpart (@$fparts)
		{
		print qq{<td>$fpart</td>};
		}
	print qq{</tr>\n};
	}
print qq{</tbody></table><br />\n\n};
}


1;
